﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Security;
using System.Security.Principal;

namespace SPMS.Log.Utility
{
    /// <summary>
    /// 执行点类
    /// </summary>
    /// <remarks>获得程序当前的执行点信息</remarks>
    /// <history>
    /// [zanezeng]               2009/9/30 14:05    创建
    /// </history>
    public sealed class ExecutingLocation
    {
        #region ---Constructor

        /// <summary>
        /// 初始化类型<see cref="ExecutingLocation"/>的新实例
        /// </summary>
        /// <param name="stackBoundaryType">堆栈分界类型</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="stackBoundaryType"/>为Null</exception>
        /// <history>
        /// [zanezeng]               2009/9/30 14:08    创建
        /// </history>
        public ExecutingLocation( Type stackBoundaryType )
        {
            //断言参数
            if (null == stackBoundaryType)
            {
                //抛出异常
                throw new ArgumentNullException( "stackBoundaryType" );
            }

            //初始化
            this.Intialize( stackBoundaryType );
        }

        #endregion

        #region ---Property

        /// <summary>
        /// 获得正在执行的类型信息
        /// </summary>
        /// <value>正在执行的类型信息</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:19    创建
        /// </history>
        public Type ExecutingType
        {
            get
            {
                return this.m_ExecutingType;
            }
        }

        /// <summary>
        /// 获得正在执行的方法信息
        /// </summary>
        /// <value>正在执行的方法信息</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:19    创建
        /// </history>
        public MethodBase ExecutingMethod
        {
            get
            {
                return this.m_ExecutingMethod;
            }
        }

        /// <summary>
        /// 获得正在执行的文件名称
        /// </summary>
        /// <value>正在执行的文件名称</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:20    创建
        /// </history>
        public string FileName
        {
            get
            {
                return this.m_FileName;
            }
        }

        /// <summary>
        /// 获得正在执行的行的行号
        /// </summary>
        /// <value>正在执行的行的行号</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:20    创建
        /// </history>
        public int LineNumber
        {
            get
            {
                return this.m_LineNumber;
            }
        }

        /// <summary>
        /// 获得正在执行的列的列号
        /// </summary>
        /// <value>正在执行的列的列号</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:21    创建
        /// </history>
        public int ColumnNumber
        {
            get
            {
                return this.m_ColumnNumber;
            }
        }

        /// <summary>
        /// 获得执行点所在线程名称
        /// </summary>
        /// <value>执行点所在线程名称</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:32    创建
        /// </history>
        public string ThreadName
        {
            get
            {
                return this.m_ThreadName;
            }
        }

        /// <summary>
        /// 获得执行点所在应用程序域的名称
        /// </summary>
        /// <value>执行点所在应用程序域的名称</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:32    创建
        /// </history>
        public string DomainName
        {
            get
            {
                return this.m_DomainName;
            }
        }

        /// <summary>
        /// 获得当前已登录到Windows操作系统的用户的用户名
        /// </summary>
        /// <value>当前已登录到Windows操作系统的用户的用户名</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:34    创建
        /// </history>
        public string CurrentWindowsUsername
        {
            get
            {
                return this.m_Username;
            }
        }

        /// <summary>
        /// 获得当前已经登录到系统的用户的用户名
        /// </summary>
        /// <value>当前已经登录到系统的用户的用户名</value>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:34    创建
        /// </history>
        public string CurrentSystemUsername
        {
            get
            {
                return this.m_Identity;
            }
        }

        #endregion

        #region ---Private Method

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="stackBoundaryType">堆栈分界类型</param>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:10    创建
        /// </history>
        private void Intialize( Type stackBoundaryType )
        {
            //设置线程名
            this.m_ThreadName = Thread.CurrentThread.ManagedThreadId.ToString( "G" );

            //获得应用程序域的名称
            this.m_DomainName = AppDomain.CurrentDomain.FriendlyName;

            //获得用户标识
            this.m_Identity = GetCurrentIdentity();

            //获得当前登陆用户名称
            this.m_Username = GetCurrentWindowsUsername();

            //后的最后一帧调用栈
            StackFrame frame = GetLatestCallStackFrame( stackBoundaryType );

            //判断是否有堆栈信息
            if (null == frame)
            {
                //如果没有堆栈信息，则直接返回
                return;
            }

            //初始化字段
            this.m_ExecutingMethod = frame.GetMethod();

            //判断是否有执行方法
            if (null != this.m_ExecutingMethod)
            {
                //设置执行类型
                this.m_ExecutingType = this.m_ExecutingMethod.DeclaringType;
            }

            //获得文件名称
            this.m_FileName = frame.GetFileName();

            //获得行号
            this.m_LineNumber = frame.GetFileLineNumber();

            //获得列号
            this.m_ColumnNumber = frame.GetFileColumnNumber();
        }

        /// <summary>
        /// 获得系统当前登陆用户名称
        /// </summary>
        /// <returns>系统当前登陆用户名称</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:27    创建
        /// </history>
        private static string GetCurrentIdentity()
        {
            //用于保存名称
            string identity = string.Empty;

            //获得登陆用户名称
            try
            {
                //获得用户标识
                if (null != Thread.CurrentPrincipal &&
                    null != Thread.CurrentPrincipal.Identity &&
                    null != Thread.CurrentPrincipal.Identity.Name)
                {
                    //记录用户标识
                    identity = System.Threading.Thread.CurrentPrincipal.Identity.Name;
                }
                else
                {
                    //设置为空字符串
                    identity = string.Empty;
                }
            }
            catch (SecurityException ex)
            {
                //输出日志
                if (LoggingContext.MetaLog.IsErrorEnabled)
                {
                    LoggingContext.MetaLog.Error( ex, "获得当前系统用户的标识名称失败" );
                }

                //设置为空字符串
                identity = string.Empty;
            }

            //返回获得用户名称
            return identity;
        }

        /// <summary>
        /// 获得当前Windows登陆用户名称
        /// </summary>
        /// <returns>当前Windows登陆用户名称</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/30 14:30    创建
        /// </history>
        private static string GetCurrentWindowsUsername()
        {
            //用于保存用户名称
            string username = string.Empty;

            //获得登陆用户名称
            try
            {
                //获得当前登录的用户
                WindowsIdentity identity = WindowsIdentity.GetCurrent();

                //判断是否为NULL
                if (null != identity)
                {
                    //记录登录用户名称
                    username = identity.Name;
                }
                else
                {
                    //设置为空字符串
                    username = string.Empty;
                }
            }
            catch (SecurityException ex)
            {
                //输出日志
                if (LoggingContext.MetaLog.IsErrorEnabled)
                {
                    LoggingContext.MetaLog.Error( ex, "获得当前已登录到Windows操作系统的人员的用户名失败" );
                }

                //设置为空字符串
                username = string.Empty;
            }

            //返回用户名称
            return username;
        }

        /// <summary>
        /// 获得最后一帧调用堆栈帧
        /// </summary>
        /// <param name="stackBoundaryType">调用堆栈的分界类型</param>
        /// <returns>最后一帧调用堆栈帧</returns>
        /// <remarks></remarks>
        /// <history>
        /// [zanezeng]               2009/9/29 11:04    创建
        /// </history>
        private static StackFrame GetLatestCallStackFrame( Type stackBoundaryType )
        {
            //创建调用堆栈跟踪
            StackTrace trace = new StackTrace( true );

            //判断是否有分界类型
            if (null == stackBoundaryType)
            {
                //如果没有，则返回第一帧
                if (trace.FrameCount > 0)
                {
                    return trace.GetFrame( 0 );
                }
                else
                {
                    return null;
                }
            }

            //用于保存调用帧序号
            int index = trace.FrameCount - 1;

            //用于保存调用帧
            StackFrame frame = null;

            //获得分界类型开始的第一个调用帧
            while (index >= 0)
            {
                //获得调用帧
                frame = trace.GetFrame( index );

                //判断是否为分界类型的调用帧
                if (null != frame && frame.GetMethod().ReflectedType == stackBoundaryType)
                {
                    //中断循环
                    break;
                }

                //减少序号
                index--;
            }

            //获得第一个不是分界类型的调用帧
            while (index < trace.FrameCount)
            {
                //获得调用帧
                frame = trace.GetFrame( index );

                //判断是否为分界类型的调用帧
                if (null != frame && frame.GetMethod().ReflectedType != stackBoundaryType)
                {
                    //返回调用帧
                    return frame;
                }

                //增加序号
                index++;
            }

            //默认返回NULL
            return null;
        }

        #endregion

        #region ---Field

        /// <summary>
        /// 正在执行的类型
        /// </summary>
        private Type m_ExecutingType;

        /// <summary>
        /// 正在执行的方法
        /// </summary>
        private MethodBase m_ExecutingMethod;

        /// <summary>
        /// 正在执行的文件名称
        /// </summary>
        private string m_FileName;

        /// <summary>
        /// 正在执行的行号
        /// </summary>
        private int m_LineNumber = -1;

        /// <summary>
        /// 正在执行的列号
        /// </summary>
        private int m_ColumnNumber = -1;

        /// <summary>
        /// 当前已登录到Windows操作系统的人员的用户名
        /// </summary>
        private string m_Username;

        /// <summary>
        /// 当前系统用户的标识名称
        /// </summary>
        private string m_Identity;

        /// <summary>
        /// 日志事件发生点所在线程的名称
        /// </summary>
        private string m_ThreadName;

        /// <summary>
        /// 应用程序域的名称
        /// </summary>
        private string m_DomainName;

        #endregion
    }
}
